﻿using Core.Variants;
using System.Collections.Generic;

namespace Core
{
    public class VariantSystem : Component, IAwake
    {
        private readonly Dictionary<long, VariantInfo> dict = new();
        private readonly Dictionary<(string, string), long> hash = new();
        private readonly VSortSet sequence = new();

        private const string ListPath = "vv_variants/list.txt";

        public void Awake()
        {
            log.err("VariantSystem.Awake");
            LoadPersistentData();
        }

        public override void Dispose()
        {
            if (IsDisposed) return;
            base.Dispose();
        }

        private void LoadPersistentData()
        {
            var str = S.File.Read(ListPath);
            var md5_arr = str.Split('\n');

            foreach (var item in md5_arr)
            {
                var md5 = item.Trim();
                if (string.IsNullOrWhiteSpace(md5)) continue;

                var json = S.File.Read($"vv_variants/{md5}");
                var variant = Utils.Json.Deserialize<VariantInfo>(json);
                if (dict.ContainsKey(variant.Id))
                {
                    continue;
                }

                sequence.Push(variant.GameName, variant.Id);

                dict[variant.Id] = variant;
                hash[(variant.GameName, variant.Md5)] = variant.Id;
            }
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="game_name"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool Push(string game_name, IVariantData data)
        {
            log.err($"VariantSystem.Push {game_name}");
            var jsonData = Utils.Json.Serialize(data);
            var variant = new VariantInfo
            {
                Id = Utils.ID.Get(),
                JsonData = jsonData,
                Md5 = Utils.Hash.DoText(jsonData),
                GameName = game_name,
                Utc = Utils.Time.Now(),
            };

            if (hash.ContainsKey((variant.GameName, variant.Md5)))
            {
                return false;
            }

            S.File.Append(ListPath, variant.Md5);
            S.File.Write($"vv_variants/{variant.Md5}", Utils.Json.Serialize(variant));

            sequence.Push(variant.GameName, variant.Id);

            dict[variant.Id] = variant;
            hash[(variant.GameName, variant.Md5)] = variant.Id;

            return true;
        }

        public VariantInfo Pop(string game_name = "")
        {
            if (sequence.Count == 0)
            {
                foreach (var pair in dict)
                {
                    sequence.Push(pair.Value.GameName, pair.Value.Id);
                }
            }

            var id = sequence.Pop(game_name);

            if (id == 0)
            {
                return null;
            }

            var variant = dict[id];

            return variant;
        }
    }
}
